package zcj.stu;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockPart;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.DefaultDataBinderFactory;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class C21 {
   /* org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@3730ab42
    org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@537c8c7e
    org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@7308ffff
    org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@6601cc93
    org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@54d901aa
    org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@63716833
    org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@573284a5
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@3fbfbf84
    org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@23f72d88
    org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@4bafe935
    org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@87b5b49
    org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@4a7a965d
    org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@507b79f7
    org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver@64a9d48c
    org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver@365a6a43
    org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@288cdaab
    org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver@23b3aa8c
    org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@99407c2
    org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver@6c796cc1
    org.springframework.web.method.annotation.ModelMethodProcessor@226eba67
    org.springframework.web.method.annotation.MapMethodProcessor@1cb7936c
    org.springframework.web.method.annotation.ErrorsMethodArgumentResolver@35342d2f
    org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver@128c502c
    org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver@45667d98
    zcj.stu.TokenArgumentResolver@65eabaab
    org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@7123be6c
    org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@1de9d54*/
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
        //准备请求
        HttpServletRequest request = readyRequest();
        //要点1.准备控制器方法 HandleMethod
        HandlerMethod method = new HandlerMethod(new Controller(), Controller.class.getMethod("researchArgumentResolver", String.class, String.class, int.class, String.class, MultipartFile.class, int.class, String.class, String.class, String.class, HttpServletRequest.class, User.class, User.class, User.class));
        //要点2.准备类型绑定与类型转换
        ServletRequestDataBinderFactory dataBinderFactory = new ServletRequestDataBinderFactory(null,null);
        //要点3.准备ModelAndViewContainer 用来存储中间Model结果
        ModelAndViewContainer container = new ModelAndViewContainer();
        //要点4.
        for (MethodParameter parameter : method.getMethodParameters()) {
            String collect = Arrays.stream(parameter.getParameterAnnotations()).map(((a) -> a.annotationType().getSimpleName())).collect(Collectors.joining());
            String annotation = collect.length()>0 ? "@" + collect + " " :" ";

            //体现了组合设计模式
            HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
            composite.addResolvers(
                    new RequestParamMethodArgumentResolver(beanFactory,false),
                    new PathVariableMethodArgumentResolver(),
                    new RequestHeaderMethodArgumentResolver(beanFactory),
                    new ServletCookieValueMethodArgumentResolver(beanFactory),
                    new ExpressionValueMethodArgumentResolver(beanFactory),
                    new ServletRequestMethodArgumentResolver(),
                    new ServletModelAttributeMethodProcessor(false),
                    new RequestResponseBodyMethodProcessor(List.of(new MappingJackson2HttpMessageConverter())),
                    new ServletModelAttributeMethodProcessor(true),
                    new RequestParamMethodArgumentResolver(beanFactory,true)
            );
            parameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
            if(composite.supportsParameter(parameter)){
                Object r = composite.resolveArgument(parameter, container, new ServletWebRequest(request), dataBinderFactory);
//                System.out.println(r.getClass());
                System.out.println("模型数据："+container.getModel());
                System.out.println("["+parameter.getParameterIndex()+"] "+annotation+parameter.getParameterType().getSimpleName()+" "+parameter.getParameterName()+"->"+r);
            }else {
                System.out.println("["+parameter.getParameterIndex()+"] "+annotation+parameter.getParameterType().getSimpleName()+" "+parameter.getParameterName());
            }
        }
        //要点5.
    }
    public static HttpServletRequest readyRequest(){
        MockHttpServletRequest request=new MockHttpServletRequest();
        request.setParameter("name1","zs");
        request.setParameter("name2","ls");
        request.addPart(new MockPart("file","abc","part".getBytes(StandardCharsets.UTF_8)));
        Map<String, String> uriTemplateVariables = new AntPathMatcher().extractUriTemplateVariables("/test/{id}", "/test/123");
        System.out.println(uriTemplateVariables);
        request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,uriTemplateVariables);
        request.setContentType("application/json");
        request.setCookies(new Cookie("token","zcj"));
        request.setParameter("name","展示");
        request.setParameter("age","18");
//        request.setContent("'''\n{ 'name':'李四', 'age':20}\n'''".getBytes(StandardCharsets.UTF_8));
        return  new StandardServletMultipartResolver().resolveMultipart(request);
    }
    static class Controller{
        public void researchArgumentResolver(
                @RequestParam("name1")String name1,
                String name2,
                @RequestParam("age")int age,
                @RequestParam(name = "java_home",defaultValue = "${JAVA_HOME}")String javaHome,
                @RequestParam("file")MultipartFile file,
                @PathVariable("id")int id,
                @RequestHeader("Content-Type")String header,
                @CookieValue("token")String token,
                @Value("${JAVA_HOME}")String javaHome2,
                HttpServletRequest request,
                @ModelAttribute("user1") User user1,
                User user2,
                @RequestBody User user3
                ){
            System.out.println("C21研究参数解析器...");
        }
    }
}
